#include "preHeader.h"
#include "MapInstanceWorker.h"
#include "InstanceMgr.h"

MapInstanceWorker::MapInstanceWorker()
: m_loadValue(0)
{
}

MapInstanceWorker::~MapInstanceWorker()
{
	MapInstance* pMapInstance = NULL;
	while (m_MapInsertPool.Dequeue(pMapInstance)) {
		delete pMapInstance;
	}
	for (auto pMapInstance : m_MapInstances) {
		delete pMapInstance;
	}
}

void MapInstanceWorker::AddMapInstance(MapInstance* pMapInstance)
{
	m_MapInsertPool.Enqueue(pMapInstance);
	m_loadValue.fetch_add(EvalMapInstanceLoadValue(pMapInstance));
}

bool MapInstanceWorker::Initialize()
{
	time_slice_ms_ = 67;
	time_max_frame_ms_ = 160;
	time_tick_slice_ms_ = 3000;
	return FrameWorker::Initialize();
}

void MapInstanceWorker::Update(uint64 diffTime)
{
	DynamicPushMapInstance();

	for (auto pMapInstance : m_MapInstances) {
		TRY_BEGIN {
			if (!pMapInstance->IsShutdown()) {
				pMapInstance->Update(diffTime);
			}
		} TRY_END
		CATCH_BEGIN(const IException &e) {
			const auto& instGuid = pMapInstance->getInstGuid();
			WLOG("Update MapInstance[%hu,%hu,%u] exception occurred.",
				instGuid.TID, instGuid.MAPID, instGuid.UID);
			e.Print();
		} CATCH_END
		CATCH_BEGIN(...) {
			const auto& instGuid = pMapInstance->getInstGuid();
			WLOG("Update MapInstance[%hu,%hu,%u] unknown exception occurred.",
				instGuid.TID, instGuid.MAPID, instGuid.UID);
		} CATCH_END
	}
}

void MapInstanceWorker::OnTick()
{
	CleanMapInstance();
}

void MapInstanceWorker::DynamicPushMapInstance()
{
	MapInstance* pMapInstance = NULL;
	const size_t n = m_MapInsertPool.GetSize();
	for (size_t i = 0; i < n && m_MapInsertPool.Dequeue(pMapInstance); ++i) {
		if (pMapInstance->GetTaskWaitInitCnt() <= 0) {
			m_MapInstances.push_back(pMapInstance);
			pMapInstance->Start();
		} else {
			m_MapInsertPool.Enqueue(pMapInstance);
		}
	}
}

void MapInstanceWorker::CleanMapInstance()
{
	for (auto itr = m_MapInstances.begin(); itr != m_MapInstances.end();) {
		auto pMapInstance = *itr;
		if (pMapInstance->IsShutdown() && pMapInstance->IsDeletable()) {
			itr = m_MapInstances.erase(itr);
			m_loadValue.fetch_sub(EvalMapInstanceLoadValue(pMapInstance));
			sInstanceMgr.RemoveInstance(pMapInstance);
		} else {
			++itr;
		}
	}
}

uint32 MapInstanceWorker::EvalMapInstanceLoadValue(MapInstance* pMapInstance)
{
	switch ((MapInfo::Type)pMapInstance->getMapType()) {
	case MapInfo::Type::WorldMap:
		return 100;
	default:
		return 1;
	}
}
